#pragma once

/*
 * raft_core 的实现
 */


#include <async_simple/coro/Lazy.h>
#include <async_simple/executors/SimpleExecutor.h>
#include <grpcpp/server_context.h>
#include <grpcpp/support/status.h>

#include <chrono>
#include <memory>
#include <mutex>
#include <vector>

#include "raft_core/ApplyMsg.h"
#include "raft_core/RaftSender.h"
#include "raft_middleware/rpc_proto/middleware_rpc.grpc.pb.h"
#include "raft_middleware/rpc_proto/middleware_rpc.pb.h"
#include "raft_utils/Command.h"
#include "raft_utils/Persistence.h"
#include "rpc_proto/raft_rpc.grpc.pb.h"
#include "state_machine/StateMachine.h"

namespace raft::core {
    class RaftCore final : public raft_rpc_protoc::RaftRPC::Service,
                           public middleware_rpc_proto::MiddlewareService::Service {
    public:
        // 初始化要传入当前节点的状态机和该状态机要应用的日志
        explicit RaftCore(std::shared_ptr<state_machine::StateMachine> state_machine,
                          std::shared_ptr<utils::Command> command);

        /* --- raft core 部分 --- */

        /* -- 选举流程 -- */
        // 在 leader 选举阶段候选人发起请求投票的具体实现
        grpc::Status
        request_election(grpc::ServerContext* context,
                         const raft_rpc_protoc::RequestElection* request,
                         raft_rpc_protoc::RequestElectionReply* reply) override;

        /* -- 日志复制与心跳机制 -- */
        // 对应 leader 向 follower 复制日志或者发送心跳的具体实现
        grpc::Status
        append_entries(grpc::ServerContext* context,
                       const raft_rpc_protoc::AppendEntries* request,
                       raft_rpc_protoc::AppendEntriesReply* reply) override;
        // leader 向 follewer 发送安装快照的具体实现
        grpc::Status install_snapshot(grpc::ServerContext* context,
                                      const raft_rpc_protoc::InstallSnapshot* request,
                                      raft_rpc_protoc::InstallSnapshotReply* reply) override;


        /* --- raft middleware 调用部分 --- */
        grpc::Status execute_command(grpc::ServerContext* context,
                                     const middleware_rpc_proto::ExecuteCommand* request,
                                     middleware_rpc_proto::ExecuteCommandReply* reply) override;

    private:
        /* --- raft core 部分 --- */

        /* -- 选举流程 -- */
        // 选举定时器，监控是否发起选举
        async_simple::coro::Lazy<void> election_timer();
        // 实际发起选举
        void initiate_election();
        // 向节点发送选举请求
        async_simple::coro::Lazy<bool>
        send_request_election(int server,
                              std::shared_ptr<raft_rpc_protoc::RequestElection> request,
                              std::shared_ptr<raft_rpc_protoc::RequestElectionReply> reply,
                              std::shared_ptr<std::atomic<int>> vote_num);


        /* -- 日志复制与心跳机制 -- */
        // leader 节点的定时心跳任务
        async_simple::coro::Lazy<void> leader_heartbeat_timer();
        // 发送或日志复制（只有 leader 才需发送心跳，向其他节点表明自己存活）
        async_simple::coro::Lazy<void> initiate_heartbeat();
        // 向节点发送复制日志或者发送心跳请求
        async_simple::coro::Lazy<bool>
        send_append_entries(int server,
                            std::shared_ptr<raft_rpc_protoc::AppendEntries>& request,
                            std::shared_ptr<raft_rpc_protoc::AppendEntriesReply>& reply,
                            std::shared_ptr<std::atomic<int>> append_nums);

        // 同步快照信息给其他节点
        async_simple::coro::Lazy<bool>
        send_install_snapshot(int server,
                              std::shared_ptr<raft_rpc_protoc::InstallSnapshot>& request,
                              std::shared_ptr<raft_rpc_protoc::InstallSnapshotReply>& reply);


        /* -- 持久化函数 -- */
        // 序列化当前节点的内容用于持久化
        std::string serialize_data();
        // 持久化当前状态
        void persistence();
        // 读取持久化数据
        void read_persistence(const std::string& data);

        /* -- 快照函数 -- */
        // 获取当前 raft 节点状态数据大小
        long long get_raft_state_size();
        // 只保留索引大于 index 的日志条目，更新节点状态，并保存快照
        void save_snapshot(int index, const std::string& state_machine_snapshot);
        // 恢复状态机快照
        void restore_state_machine_snapshot(const std::string& snapshot);

        /* -- 日志函数 -- */
        // 获取最后一条日志索引
        int get_last_log_index();
        // 获取最后一条日志的任期号
        int get_last_log_term();
        // 判断节点的日志是否为最新日志
        bool is_latest(int index, int term);
        // 将日志索引转换为日志条目在logs_数组中的位置
        int get_slices_index_by_log_index(int log_index);
        // 获取指定服务器的前一个日志的索引号和任期号
        void get_prev_log_info(int server, int* pre_index, int* pre_term);
        // 根据给定日志索引获取对应任期号
        int get_log_term_by_log_index(int log_index);
        // 检查日志索引和任期号是否匹配
        bool is_log_match(int log_index, int log_term);

        /* -- 将日志应用到状态机 -- */
        // 寻找可以提交给状态机的日志
        void find_apply_log_timer();
        // 提交给状态机
        void apply_log(ApplyMsg& log_msg);


        // 互斥锁
        std::mutex mutex_;

        // 当前节点的标识
        std::string me_;
        // 其他 raft 节点通讯
        std::vector<std::unique_ptr<RaftSender>> peers_;
        // 节点身份枚举（跟随者、候选者、领导者）
        enum class Status {
            Follower,
            Candidate,
            Leader
        };
        // 当前节点的身份
        Status status_;


        /* -- 需要持久化的数据 -- */
        // 当前任期
        int current_term_;
        // 当前节点在当前任期中投票给了哪个节点（没有则为空）
        std::string voted_for_;
        // raft 日志条目数组
        std::vector<raft_rpc_protoc::LogEntry> logs_;
        // 快照中的最后一个日志的任期
        int last_snapshot_include_term_;
        // 快照中的最后一个日志的索引
        int last_snapshot_include_index_;

        /* -- 日志数据 -- */
        std::unique_ptr<ApplyMsg> apply_msg_;

        /* -- 临时数据 -- */
        // 已提交的日志条目索引，标识哪些日志已经被确定可以应用到状态机
        int commit_index_;
        // 已经汇报给状态机的日志索引，用于跟踪哪些日志已经被处理并应用到上层业务逻辑中
        int last_applied_;
        // leader 节点标识
        std::string leader_me_;

        /* -- 只属于 leader 的临时数据 -- */
        // 下一个将要发送给对应节点的日志条目的索引，用于节点间日志同步等操作
        std::vector<int> next_index_;
        // 已经发送同步的日志条目索引
        std::vector<int> match_index_;

        /* -- 时间相关数据 -- */
        // 上次选举重置时间
        std::chrono::system_clock::time_point last_election_reset_time_;
        // 上次重置心跳时间
        std::chrono::system_clock::time_point last_heartbeat_reset_time_;

        /* -- 持久化相关的数据 -- */
        // 持久化相关指针
        std::unique_ptr<utils::Persistence> persistence_;

        /* -- 当前节点的状态机 -- */
        std::shared_ptr<state_machine::StateMachine> state_machine_;
        std::shared_ptr<utils::Command> command_;

        // 协程调度器
        async_simple::executors::SimpleExecutor executor_;

        bq::log log;
    };
}// namespace raft::core